﻿#region Copyright (c) 2010 R. Uittenbosch
/*
* Copyright (C) 2010 R. Uittenbosch
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 
* associated documentation files (the "Software"), to deal in the Software without restriction, including 
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
* copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the 
* following conditions:
* 
* The above copyright notice and this permission notice shall be included in all copies or substantial 
* portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 
* LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO 
* EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#endregion

//-----------------------------------------------------------------------
// <copyright file="LinkedInService.cs" company="Beemway">
//     Copyright (c) Beemway. All rights reserved.
// </copyright>
// <license>
//     Microsoft Public License (Ms-PL http://opensource.org/licenses/ms-pl.html).
//     Contributors may add their own copyright notice above.
// </license>
//-----------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Net;
using System.Text;
using System.Xml;
using System.Xml.Serialization;


using LinkedService.Mobile.ServiceEntities;
using LinkedService.Mobile.Utility;
using OAuth.Net.Mobile.Common;
using OAuth.Net.Mobile.Consumer;
using System.Globalization;

namespace LinkedService.Mobile
{

  /// <summary>
  /// A service to access the LinkedIn API's.
  /// </summary>
  public class LinkedInService
  {

    #region Properties
    /// <summary>
    /// Gets or sets the object that can send authorized requests.
    /// </summary>
    private IDataRepository Repository { get; set; }
    private ErrorEventArgs _lastError { get; set; }

    #endregion
   
    #region Constructor

    /// <summary>
    /// Initializes a new instance of the <see cref="LinkedInService"/> class.
    /// </summary>
    /// <param name="repository">The object that can send requests.</param>
    public LinkedInService(IDataRepository repository)
    {
      this.Repository = repository;
      this.Repository.OnError   += new ErrorEventHandler(IDataRepository_OnError);
      this.Repository.OnSuccess += new EventHandler(IDataRepository_OnSuccess);
    }

    #endregion

    #region Public
    
    /// <summary>
    /// Was the last call succesfull.
    /// </summary>
    public bool Succesfull { get; private set; }

    /// <summary>
    /// In case of an unsuccesfull call, what is the last error.
    /// </summary>
    public ErrorEventArgs LastError 
    {     
      get 
      {
        if (!string.IsNullOrEmpty(this.Repository.LastRawContent))
          try { _lastError.Error = this.Repository.LastRawContent.DeserializeXml<Error>(); } catch { }

        if (string.IsNullOrEmpty(_lastError.Message))
        {
          if (_lastError.Error != null)
            _lastError.Message = _lastError.Error.Message;
          else if (_lastError.Exception != null)
          {
            _lastError.Message = _lastError.Exception.Message;
            if (_lastError.Exception as OAuthRequestException != null)
            {
              OAuthRequestException e = _lastError.Exception as OAuthRequestException;
              _lastError.Message =  e.Message + e.Problem + e.Advice;
            }          
          }
          else
            _lastError.Message = "Unknown error";
        }      
        return _lastError;
      } 
      private set 
      {
        _lastError = value; 
      } 
    }
 

    /// <summary>
    /// Security Interface
    /// </summary>
    public IDataRepositorySecurity Security { get { return Repository as IDataRepositorySecurity; } }

    #endregion

    #region Profile API

    /// <summary>
    /// Get the full profile of the  current user.
    /// </summary>
    /// <returns></returns>
    public Person GetCurrentUserF()
    {
      return GetProfile(this.BuildApiUrl(), new List<string>() { "id", "first-name", "last-name", "headline", "picture-url", "industry", "current-status", "educations", "positions", "specialties", "summary", "associations", "honors" });
    }
    /// <summary>
    /// Retrieve the current user his profile.
    /// </summary>
    /// <returns>A <see cref="Person"/> representing the current user.</returns>
    public Person GetCurrentUser()
    {      
        return GetProfile(this.BuildApiUrl(), null);
    }

    /// <summary>
    /// Retrieve the current user his profile.
    /// </summary>
    /// <param name="fields">A list of profile fields to retrieve.</param>
    /// <returns>A <see cref="Person"/> representing the current user.</returns>
    public Person GetCurrentUser(List<string> fields)
    {
      UriBuilder locationBaseUri = BuildApiUrl();

      return GetProfile(locationBaseUri, fields);
    }

    /// <summary>
    /// Get the full profile for a member
    /// </summary>
    /// <param name="memberId"></param>
    /// <returns></returns>
    public Person GetProfileByMemberIdF(string memberId)
    {
      return GetProfileByMemberId(memberId, new List<string>() { "id", "first-name", "last-name", "headline", "picture-url", "industry", "current-status", "educations", "positions", "specialties", "summary", "distance", "associations", "honors", "three-current-positions", "three-past-positions", "relation-to-viewer" });
    }

    /// <summary>
    /// Get the minimal profile for a member
    /// </summary>
    /// <param name="memberId"></param>
    /// <returns></returns>
    public Person GetProfileByMemberIdM(string memberId)
    {
      return GetProfileByMemberId(memberId, new List<string>() { "id", "first-name", "last-name", "distance" });
    }

    /// <summary>
    /// Retrieve a profile for a member.
    /// </summary>
    /// <param name="memberId">The identifier for the member.</param>
    /// <returns>A <see cref="Person"/> representing the member.</returns>
    public Person GetProfileByMemberId(string memberId)
    {
      return GetProfileByMemberId(memberId, null);
    }

    /// <summary>
    /// Retrieve a profile for a member.
    /// </summary>
    /// <param name="memberId">The identifier for the member.</param>
    /// <param name="fields">A list of Profile fields to retrieve.</param>
    /// <returns>A <see cref="Person"/> representing the member.</returns>
    public Person GetProfileByMemberId(string memberId, List<string> fields)
    {
      UriBuilder location = BuildApiUrlByMemberId(memberId);

      return GetProfile(location, fields);
    }

    /// <summary>
    /// Retrieve a profile for a member.
    /// </summary>
    /// <param name="profileUrl">The profile url identifing the user.</param>
    /// <returns>A <see cref="Person"/> representing the member.</returns>
    public Person GetProfileByPublicProfileUrl(string profileUrl)
    {
      return GetProfileByPublicProfileUrl(profileUrl, null);
    }

    /// <summary>
    /// Retrieve a profile for a member.
    /// </summary>
    /// <param name="profileUrl">The profile url identifing the user.</param>
    /// <param name="fields">A list of Profile fields to retrieve.</param>
    /// <returns>A <see cref="Person"/> representing the member.</returns>
    public Person GetProfileByPublicProfileUrl(string profileUrl, List<string> fields)
    {
      UriBuilder location = BuildApiUrlByPublicProfileUrl(profileUrl);

      return GetProfile(location, fields);
    }

    /// <summary>
    /// Retrieve a profile for a member.
    /// </summary>
    /// <param name="location">The uri represented by a <see cref="UriBuilder"/> object to append to.</param>
    /// <param name="fields">A list of Profile fields to retrieve.</param>
    /// <returns>A <see cref="Person"/> representing the member.</returns>
    private Person GetProfile(UriBuilder location, List<string> fields)
    {
      location.AppendPathParameters(fields);
      return this.Repository.RetrieveContent<Person>(location.Uri.ToString());
    }
    #endregion

    #region Connections API
    /// <summary>
    /// Retrieve the connections for the current user.
    /// </summary>
    /// <returns>A <see cref="Connections"/> object representing the connections.</returns>
    public Connections GetConnectionsForCurrentUser()
    {
      return GetConnectionsForCurrentUser(null, -1, -1);
    }

    /// <summary>
    /// Retrieve the connections for the current user.
    /// </summary>
    /// <param name="fields">A list of Profile fields to retrieve.</param>
    /// <param name="start">Starting location within the result set for paginated returns</param>
    /// <param name="count">Number of results to return.</param>
    /// <returns>A <see cref="Connections"/> object representing the connections.</returns>
    public Connections GetConnectionsForCurrentUser(List<string> fields, int start, int count)
    {
      UriBuilder location = BuildApiUrl(Constants.ConnectionsMethod);

      return GetConnections(location, fields, start, count);
    }

    /// <summary>
    /// Retrieve the connections for the current user.
    /// </summary>
    /// <param name="memberId">The identifier for the member.</param>
    /// <returns>A <see cref="Connections"/> object representing the connections.</returns>
    public Connections GetConnectionsByMemberId(string memberId)
    {
      return GetConnectionsByMemberId(memberId, null, -1, -1);
    }

    /// <summary>
    /// Retrieve the connections a member.
    /// </summary>
    /// <param name="memberId">The identifier for the member.</param>
    /// <param name="fields">A list of Profile fields to retrieve.</param>
    /// <param name="start">Starting location within the result set for paginated returns</param>
    /// <param name="count">Number of results to return.</param>
    /// <returns>A <see cref="Connections"/> object representing the connections.</returns>
    public Connections GetConnectionsByMemberId(string memberId, List<string> fields, int start, int count)
    {
      UriBuilder location = BuildApiUrlByMemberId(memberId, Constants.ConnectionsMethod);

      return GetConnections(location, fields, start, count);
    }

    /// <summary>
    /// Retrieve the connections a member.
    /// </summary>
    /// <param name="location">The uri represented by a <see cref="UriBuilder"/> object to append to.</param>
    /// <param name="fields">A list of Profile fields to retrieve.</param>
    /// <param name="start">Starting location within the result set for paginated returns</param>
    /// <param name="count">Number of results to return.</param>
    /// <returns>A <see cref="Connections"/> object representing the connections.</returns>
    private Connections GetConnections(UriBuilder location, List<string> fields, int start, int count)
    {
      if (location == null)
      {
        throw new ArgumentNullException("location");
      }

      location.AppendPathParameters(fields);

      Collection<KeyValuePair<string, string>> parameters = new Collection<KeyValuePair<string, string>>();
      parameters.AddNonEmpty(Constants.StartParam, start);
      parameters.AddNonEmpty(Constants.CountParam, count);
      location.AppendQueryParameters(parameters);
      return this.Repository.RetrieveContent<Connections>(location.Uri.ToString());      
    }
    #endregion

    #region Network Updates API
    /// <summary>
    /// Retrieve the Network Updates for the current user.
    /// </summary>
    /// <param name="updateType">The type of Network Updates to retrieve.</param>
    /// <returns>A <see cref="Network"/> object representing the Network Updates.</returns>
    public Network GetNetworkUpdates(NetworkUpdateType updateType)
    {
      return GetNetworkUpdates(updateType, Constants.MaxNumberOfNetworkUpdates, 1, DateTime.MinValue, DateTime.MinValue);
    }

    /// <summary>
    /// Retrieve the Network Updates for the current user.
    /// </summary>
    /// <param name="updateType">The type of Network Updates to retrieve.</param>
    /// <param name="after">The <see cref="DateTime"/> after which to retrieve updates for.</param>
    /// <param name="before">The <see cref="DateTime"/> before which to retrieve updates for.</param>
    /// <returns>A <see cref="Network"/> object representing the Network Updates.</returns>
    public Network GetNetworkUpdates(NetworkUpdateType updateType, DateTime after, DateTime before)
    {
      return GetNetworkUpdates(updateType, Constants.MaxNumberOfNetworkUpdates, 1, after, before);
    }

    /// <summary>
    /// Retrieve the Network Updates for the current user.
    /// </summary>
    /// <param name="updateType">The type of Network Updates to retrieve.</param>
    /// <param name="count">Number of results to return.</param>
    /// <param name="start">Starting location within the result set for paginated returns</param>
    /// <param name="after">The <see cref="DateTime"/> after which to retrieve updates for.</param>
    /// <param name="before">The <see cref="DateTime"/> before which to retrieve updates for.</param>
    /// <returns>A <see cref="Network"/> object representing the Network Updates.</returns>
    public Network GetNetworkUpdates(NetworkUpdateType updateType, int count, int start, DateTime after, DateTime before)
    {
      Collection<KeyValuePair<string, string>> parameters = new Collection<KeyValuePair<string, string>>();

      if (updateType.Contains(NetworkUpdateType.All) == false)
      {
        // Loop through all updatetypes
        for (NetworkUpdateType t = NetworkUpdateType.AnswerUpdate; t <= NetworkUpdateType.All; t++)
        {
          if (updateType.Contains(t))
            parameters.AddNonEmpty(Constants.TypeParam, t.Description());
        }
      }
      parameters.AddNonEmpty(Constants.CountParam, count);
      parameters.AddNonEmpty(Constants.StartParam, start);

      // Due to a bug in NetworkUpdates, multiply by 1000.
      if (before != DateTime.MinValue)
        parameters.AddNonEmpty(Constants.BeforeParam, UnixTime.ToUnixTime(before)*1000);

      if (after != DateTime.MinValue)
        parameters.AddNonEmpty(Constants.AfterParam, UnixTime.ToUnixTime(after)*1000);


      UriBuilder location = BuildApiUrl(Constants.NetworkUpdatesMethod, parameters);
      return this.Repository.RetrieveContent<Network>(location.Uri.ToString());  

    }
    #endregion

    #region IDataRepository EventHandlers

    void IDataRepository_OnSuccess(object sender, EventArgs e)
    {
      this.Succesfull = true;
    }

    void IDataRepository_OnError(object sender, ErrorEventArgs e)
    {
      this.Succesfull = false;
      _lastError = e;
    }
    #endregion

    #region Search API
    /// <summary>
    /// Search for members.
    /// </summary>
    /// <param name="keywords">The keywords to search for.</param>
    /// <param name="start">Starting location within the result set for paginated returns</param>
    /// <param name="count">Number of results to return.</param>
    /// <returns>A <see cref="People"/> object representing the search result.</returns>
    public People Search(string keywords, int start, int count)
    {
      return Search(
        keywords, 
        string.Empty, 
        string.Empty, 
        false, 
        string.Empty, 
        false,
        -1, 
        SearchType.General, 
        string.Empty, 
        string.Empty, 
        SortCriteria.Ctx, 
        start, 
        count);
    }

    /// <summary>
    /// Search for members.
    /// </summary>
    /// <param name="name">The persons name to search for.</param>
    /// <param name="company">The persons company to search for.</param>
    /// <param name="start">Starting location within the result set for paginated returns</param>
    /// <param name="count">Number of results to return.</param>
    /// <returns>A <see cref="People"/> object representing the search result.</returns>
    public People SearchByNameAndCompany(string name, string company, int start, int count)
    {
      return Search(
            string.Empty,
            name,
            company,
            false,
            string.Empty,
            false,
            -1,
            SearchType.General,
            string.Empty,
            string.Empty,
            SortCriteria.Ctx,
            start,
            count);
    }

    /// <summary>
    /// Search for members.
    /// </summary>
    /// <param name="name">The persons name to search for.</param>
    /// <param name="start">Starting location within the result set for paginated returns</param>
    /// <param name="count">Number of results to return.</param>
    /// <returns>A <see cref="People"/> object representing the search result.</returns>
    public People SearchByName(string name, int start, int count)
    {
      return Search(
            string.Empty,
            name,
            string.Empty,
            false,
            string.Empty,
            false,
            -1,
            SearchType.General,
            string.Empty,
            string.Empty,
            SortCriteria.Ctx,
            start,
            count);
    }
    /// <summary>
    /// Search for members.
    /// </summary>
    /// <param name="keywords">The keywords to search for.</param>
    /// <param name="name">The name to search for.</param>
    /// <param name="company">The company to search for.</param>
    /// <param name="currentCompany">Whether the company to search for is the current company.</param>
    /// <param name="title">The title to search for.</param>
    /// <param name="currentTitle">Whether the title to search for is the current title.</param>
    /// <param name="industryCode">The industry code to search for.</param>
    /// <param name="searchType">The search type.</param>
    /// <param name="countryCode">The country code to search for.</param>
    /// <param name="postalCode">The postal code to search for.</param>
    /// <param name="sortCriteria">The sort criteria for the search results.</param>
    /// <param name="start">Starting location within the result set for paginated returns</param>
    /// <param name="count">Number of results to return.</param>
    /// <returns>A list of <see cref="Person"/> objects representing the members.</returns>
    /// <remarks>
    /// TODO: Allow multiple Industry Codes
    /// TODO: Use Industry code enums
    /// </remarks>
    private People Search(
      string keywords,
      string name,
      string company,
      bool currentCompany,
      string title,
      bool currentTitle,
      int industryCode,
      SearchType searchType,
      string countryCode,
      string postalCode,
      SortCriteria sortCriteria,
      int start,
      int count)
    {
      // TODO: Country code and postal code validation
      if (string.IsNullOrEmpty(postalCode) == false && string.IsNullOrEmpty(countryCode))
      {
        throw new ArgumentNullException("countryCode");
      }

      if (count > 10)
      {
        throw new ArgumentOutOfRangeException("count", "count out of range");
      }

      Collection<KeyValuePair<string, string>> parameters = new Collection<KeyValuePair<string, string>>();

      parameters.AddNonEmpty(Constants.KeywordsParam, keywords.Replace(" ", "+"));
      parameters.AddNonEmpty(Constants.NameParam, name.Replace(" ", "+"));
      parameters.AddNonEmpty(Constants.CompanyParam, company);
      parameters.AddNonEmpty(Constants.CurrentCompanyParam, currentCompany.ToString());
      parameters.AddNonEmpty(Constants.TitleParam, title);
      parameters.AddNonEmpty(Constants.CurrentTitleParam, currentTitle.ToString());
      parameters.AddNonEmpty(Constants.IndustryCodeParam, industryCode);
      if (searchType == SearchType.ByLocation ||
        string.IsNullOrEmpty(countryCode) == false ||
        string.IsNullOrEmpty(postalCode) == false)
      {
        parameters.AddNonEmpty(Constants.SearchLocationTypeParam, searchType.Description());
        parameters.AddNonEmpty(Constants.CountryCodeParam, countryCode);
        parameters.AddNonEmpty(Constants.PostalCodeParam, postalCode);
      }

      parameters.AddNonEmpty(Constants.SortCriteriaParam, sortCriteria.Description());
      parameters.AddNonEmpty(Constants.StartParam, start);
      parameters.AddNonEmpty(Constants.CountParam, count);

      UriBuilder location = BuildApiUrl(parameters);
      return this.Repository.RetrieveContent<People>(location.Uri.ToString());  
    }
    #endregion

    #region Status Update API
    /// <summary>
    /// Update the status of the current user.
    /// </summary>
    /// <param name="status">The new status.</param>
    public void UpdateStatus(string status)
    {
      if (string.IsNullOrEmpty(status))
      {
        DeleteStatus();
      }
      else if (status.Length > Constants.MaxStatusLength)
      {
        throw new ArgumentOutOfRangeException("status", "status out of range");
      }
      else
      {
        UriBuilder location = BuildApiUrl(Constants.StatusMethod);

        CurrentStatus currentStatus = new CurrentStatus() {  Status = status };
        string xmlresponse = this.Repository.RetrieveContent<CurrentStatus>(location.Uri.ToString(), currentStatus, HttpMethod.PUT);
        // For the status, a "NoContent" statuscode is also ok.
        if (!Succesfull)
          Succesfull = (this.Repository.LastStatusCode == HttpStatusCode.NoContent);
      }
    }

    /// <summary>
    /// Delete the current user his status.
    /// </summary>
    public void DeleteStatus()
    {
      UriBuilder location = BuildApiUrl(Constants.StatusMethod);
      string xmlResponse = this.Repository.RetrieveContent(location.Uri.ToString(), HttpMethod.DELETE);
     
    }
    #endregion

    #region Messaging And Invitation API
    /// <summary>
    /// Invite a person to the current user his network.
    /// </summary>
    /// <param name="personId">The identifier of the person to invite.</param>
    /// <param name="subject">The subject of the message that will be sent to the recipient.</param>
    /// <param name="body">The body of the message that will be sent to the recipient.</param>
    /// <param name="connectionType">The type of connection to invite the person to.</param>
    /// <param name="apiRequest">A <see cref="ApiRequest"/> object used to authorize the recipient.</param>
    /// <returns><b>true</b> if successful; otherwise <b>false</b>.</returns>
    public bool InvitePerson(string personId, string subject, string body, ConnectionType connectionType, ApiRequest apiRequest)
    {
      if (string.IsNullOrEmpty(personId))
      {
        throw new ArgumentNullException("personId");
      }

      if (string.IsNullOrEmpty(subject))
      {
        throw new ArgumentNullException("subject");
      }

      if (string.IsNullOrEmpty(body))
      {
        throw new ArgumentNullException("body");
      }

      if (apiRequest == null)
      {
        throw new ArgumentNullException("apiRequest");
      }

      List<Recipient> recipients = new List<Recipient>() 
      {
        new Recipient 
          {
            Path = string.Format(CultureInfo.InvariantCulture, "/people/id={0}", personId) 
          }
      };

      MailboxItem mailboxItem = new MailboxItem(recipients);
      mailboxItem.Subject = subject;
      mailboxItem.Body = body;
      mailboxItem.ItemContent = new Invitation
      {
        ConnectType = connectionType.Description(),
        Authorization = new KeyValuePair<string, string>(apiRequest.Headers[0].Value.Split(':')[0], apiRequest.Headers[0].Value.Split(':')[1])
      };
      // Post
      UriBuilder location = BuildApiUrl(Constants.MessageMethod);
      string xmlResponse = this.Repository.RetrieveContent<MailboxItem>(location.Uri.ToString(), mailboxItem, HttpMethod.POST);


      return this.Repository.LastStatusCode == HttpStatusCode.Created;
    }

    /// <summary>
    /// Send a message to one or more persons.
    /// </summary>
    /// <param name="subject">The subject of the message.</param>
    /// <param name="body">The body of the message.</param>
    /// <param name="memberIds">A list of member identifiers.</param>
    /// <param name="includeCurrentUser">Whether to send the message to the current user.</param>
    /// <returns><b>true</b> if successful; otherwise <b>false</b>.</returns>
    public bool SendMessage(string subject, string body, List<string> memberIds, bool includeCurrentUser)
    {
      if (memberIds == null)
      {
        if (includeCurrentUser == false)
        {
          throw new ArgumentNullException("memberIds");
        }
        else
        {
          memberIds = new List<string>();
        }
      }

      if (includeCurrentUser)
      {
        memberIds.Add(Constants.CurrentUserIdentifier);
      }

      List<Recipient> recipients = new List<Recipient>();
      foreach (string recipient in memberIds)
      {
        recipients.Add(new Recipient { Path = string.Format("/people/{0}", recipient) });
      }

      MailboxItem mailboxItem = new MailboxItem(recipients);
      mailboxItem.Subject = subject;
      mailboxItem.Body = body;

      UriBuilder location = BuildApiUrl(Constants.MessageMethod);

      string xmlResponse = this.Repository.RetrieveContent<MailboxItem>(location.Uri.ToString(), mailboxItem, HttpMethod.POST);

      Succesfull = this.Repository.LastStatusCode == HttpStatusCode.Created;
      return Succesfull;
    }
    #endregion

    #region Post Network Update API
    /// <summary>
    /// Post a Network Update.
    /// </summary>
    /// <param name="cultureName">A culture name indicating the language of the update.</param>
    /// <param name="body">The actual content of the update. You can use HTML to include links to the user name and the content the user created. Other HTML tags are not supported. All body text should be HTML entity escaped and UTF-8 compliant.</param>
    /// <returns><b>true</b> if successful; otherwise <b>false</b>.</returns>
    public bool PostNetworkUpdate(string cultureName, string body)
    {
      if (string.IsNullOrEmpty(body))
      {
        throw new ArgumentNullException("body");
      }

      if (string.IsNullOrEmpty(cultureName))
      {
        cultureName = "en-US";
      }

      Activity activity = new Activity();
      activity.CultureName = cultureName;
      activity.Body = body;

      UriBuilder location = BuildApiUrl(Constants.PostNetworkUpdateMethod);

      string xmlResponse = this.Repository.RetrieveContent<Activity>(location.Uri.ToString(), activity, HttpMethod.POST);

      Succesfull = this.Repository.LastStatusCode == HttpStatusCode.Created;
      return Succesfull;
    }
    #endregion  
  
    #region Private methods
    
    #region BuildApiUrl
    /// <summary>
    /// Initialize the url of the API.
    /// </summary>
    /// <returns>A <see cref="UriBuilder"/> object representing the url.</returns>
    public UriBuilder BuildApiUrl()
    {
      return BuildApiUrl(string.Empty, null);
    }

    /// <summary>
    /// Initialize the url of the API.
    /// </summary>
    /// <param name="parameters">A list of parameters.</param>
    /// <returns>A <see cref="UriBuilder"/> object representing the url.</returns>
    public UriBuilder BuildApiUrl(IEnumerable<KeyValuePair<string, string>> parameters)
    {
      return BuildApiUrl(string.Empty, string.Empty, parameters);
    }

    /// <summary>
    /// Initialize the url of the API.
    /// </summary>
    /// <param name="method">The API method.</param>
    /// <returns>A <see cref="UriBuilder"/> object representing the url.</returns>
    public UriBuilder BuildApiUrl(string method)
    {
      return BuildApiUrl(method, null);
    }

    /// <summary>
    /// Initialize the url of the API.
    /// </summary>
    /// <param name="method">The API method.</param>
    /// <param name="parameters">A list of parameters.</param>
    /// <returns>A <see cref="UriBuilder"/> object representing the url.</returns>
    public UriBuilder BuildApiUrl(string method, IEnumerable<KeyValuePair<string, string>> parameters)
    {
      return BuildApiUrl("~", method, parameters);
    }

    /// <summary>
    /// Initialize the url of the API.
    /// </summary>
    /// <param name="memberId">The identifier for a member.</param>
    /// <returns>A <see cref="UriBuilder"/> object representing the url.</returns>
    public UriBuilder BuildApiUrlByMemberId(string memberId)
    {
      return BuildApiUrlByMemberId(memberId, string.Empty);
    }

    /// <summary>
    /// Initialize the url of the API.
    /// </summary>
    /// <param name="memberId">The identifier for a member.</param>
    /// <param name="method">The API method.</param>
    /// <returns>A <see cref="UriBuilder"/> object representing the url.</returns>
    public UriBuilder BuildApiUrlByMemberId(string memberId, string method)
    {
      string identifier = string.Format("id={0}", memberId);
      return BuildApiUrl(identifier, method, null);
    }

    /// <summary>
    /// Initialize the url of the API.
    /// </summary>
    /// <param name="emailAddress">The identifier for a member.</param>
    /// <param name="method">The API method.</param>
    /// <returns>A <see cref="UriBuilder"/> object representing the url.</returns>
    public UriBuilder BuildApiUrlByEmailAddress(string emailAddress, string method)
    {
      string identifier = string.Format("email={0}",  HttpUtility.UrlEncode(emailAddress));
      return BuildApiUrl(identifier, method, null);
    }

    /// <summary>
    /// Initialize the url of the API.
    /// </summary>
    /// <param name="profileUrl">The identifier for a member.</param>
    /// <returns>A <see cref="UriBuilder"/> object representing the url.</returns>
    public UriBuilder BuildApiUrlByPublicProfileUrl(string profileUrl)
    {
      return BuildApiUrlByPublicProfileUrl(profileUrl, string.Empty);
    }

    /// <summary>
    /// Initialize the url of the API.
    /// </summary>
    /// <param name="profileUrl">The identifier for a member.</param>
    /// <param name="method">The API method.</param>
    /// <returns>A <see cref="UriBuilder"/> object representing the url.</returns>
    public UriBuilder BuildApiUrlByPublicProfileUrl(string profileUrl, string method)
    {
      string identifier = string.Format("url={0}", HttpUtility.UrlEncode(profileUrl));
      return BuildApiUrl(identifier, method, null);
    }

    /// <summary>
    /// Initialize the url of the API.
    /// </summary>
    /// <param name="identifier">The identifier for a member.</param>
    /// <param name="method">The API method.</param>
    /// <param name="parameters">A list of parameters.</param>
    /// <returns>A <see cref="UriBuilder"/> object representing the url.</returns>
    private UriBuilder BuildApiUrl(string identifier, string method, IEnumerable<KeyValuePair<string, string>> parameters)
    {
      if (string.IsNullOrEmpty(method) == false)
      {
        method = string.Format("/{0}", method);
      }

      UriBuilder uri = new UriBuilder(string.Format("{0}/{1}{2}", Constants.ApiBaseUrl, identifier, method));

      if (parameters != null)
      {
        return this.AppendQueryStringParameters(uri, parameters);
      }
      else
      {
        return uri;
      }
    }
    #endregion 

    /// <summary>
    /// Append a list of parameters to the Query string of an uri.
    /// </summary>
    /// <param name="location">The uri represented by a <see cref="UriBuilder"/> object to append to.</param>
    /// <param name="parameters">The parameters to append.</param>
    /// <returns>A uri represented by a <see cref="UriBuilder"/> object containing the query string parameters.</returns>
    public UriBuilder AppendQueryStringParameters(UriBuilder location, IEnumerable<KeyValuePair<string, string>> parameters)
    {
      //if (parameters.Count<KeyValuePair<string, string>>() == 0)
      //{
      //  return location;
      //}

      StringBuilder sb = new StringBuilder();
      if (string.IsNullOrEmpty(location.Query) == false)
      {
        sb.Append(location.Query.Substring(1));
      }

      foreach (KeyValuePair<string, string> pair in parameters)
      {
        sb.Append(string.Format("{0}={1}&", HttpUtility.UrlEncode(pair.Key), HttpUtility.UrlEncode(pair.Value)));        
      }

      location.Query = sb.ToString();
      return location;
    }
        
    #endregion
  }
}
